package com.hsnn.medstgmini.trading.pur.dao.impl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.hsnn.medstgmini.Constants;
import com.hsnn.medstgmini.dao.HibernateSqlUtil;
import com.hsnn.medstgmini.exception.MSException;
import com.hsnn.medstgmini.sys.model.SysUser;
import com.hsnn.medstgmini.trading.pur.dao.OrderDispatchDao;
import com.hsnn.medstgmini.trading.pur.model.OrderDetailStatus;
import com.hsnn.medstgmini.trading.pur.model.OrderPackStatus;
import com.hsnn.medstgmini.trading.pur.model.PurConfig;
import com.hsnn.medstgmini.trading.pur.model.form.DispatchInfo;
import com.hsnn.medstgmini.trading.pur.model.form.OrderDetail;
import com.hsnn.medstgmini.trading.pur.model.form.OrderPack;
import com.hsnn.medstgmini.trading.pur.model.form.OrderPackage;
import com.hsnn.medstgmini.util.AreaUtil;
import com.hsnn.medstgmini.util.DateUtil;
import com.hsnn.medstgmini.util.Pagination;

/**
 * @category 订单配送
 * @author 蔡春龙
 * @date 2015年7月14日
 */
@Repository
public class OrderDispatchDaoImpl implements OrderDispatchDao {

	@Resource(name = "sessionFactory")
	private SessionFactory factory;
	
	@Autowired
	private HibernateSqlUtil dao;
	
	/**
	 * @category 分页查询订单包信息
	 * @date 2015年7月13日
	 * @param orderPackage
	 * @param page
	 * @return
	 */
	public Pagination getOrderDispatch(OrderPackage orderPackage, Pagination page) {
		
		Session session = factory.getCurrentSession();
		StringBuffer hql = new StringBuffer();
		hql.append("select config_value from sys_purconfig where  config_id = '999821f9-23d0-11e5-9cc0-40f2e9d2c708' ");
		SQLQuery configQuery = session.createSQLQuery(hql.toString());
		Object obj = configQuery.uniqueResult();
		
		StringBuilder sb = new StringBuilder();
		sb.append(" SELECT a.remarks,a.order_pack_id orderPackId, a.hosp_code hospCode, a.hosp_name hospName,  ");
		sb.append(" a.hosp_ar_fullname hospArFullname, a.count, a.amount, a.is_urgent isUrgent, ");
		sb.append(" DATE_FORMAT(a.submit_datetime, '%Y-%m-%d %T') submitDatetime, ");
		sb.append(" a.recp_addr recpAddr, a.recp_userphone recpUserphone, a.recp_user recpUser ");
		sb.append(" FROM pur_orderpack a WHERE a.del_comp_code = :delCompCode ");
		sb.append(" AND (a.order_status = :orderStatus1 OR a.order_status = :orderStatus2) ");
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("delCompCode", orderPackage.getDelCompCode());
		params.put("orderStatus1", OrderPackStatus.confirmed.getKey());
		params.put("orderStatus2", OrderPackStatus.someDispatched.getKey());
		
		if (StringUtils.isNotBlank(orderPackage.getHospName())) {
			sb.append(" AND ( a.hosp_name LIKE :hospName OR a.hosp_spel_code LIKE :hospName ) ");
			params.put("hospName", "%" + orderPackage.getHospName() + "%");
		}
		
		if (StringUtils.isNotBlank(orderPackage.getAreaId())) {
			sb.append(" AND a.hosp_area_id LIKE :areaId ");
			params.put("areaId", AreaUtil.escapeAreaId(orderPackage.getAreaId()));
		}
		
		if (StringUtils.isNotBlank(orderPackage.getOrderPackId())) {
			sb.append(" AND a.order_pack_id = :orderPackId ");
			params.put("orderPackId", orderPackage.getOrderPackId());
		}
		
		if (orderPackage.getStartDate() != null) {
			sb.append(" AND DATE_FORMAT(a.submit_datetime, '%Y-%m-%d') >= :startDate ");
			params.put("startDate", DateUtil.date(orderPackage.getStartDate()));
		}
		
		if (orderPackage.getEndDate() != null) {
			sb.append(" AND DATE_FORMAT(a.submit_datetime, '%Y-%m-%d') <= :endDate ");
			params.put("endDate", DateUtil.date(orderPackage.getEndDate()));
		}

		if(obj != null){
			sb.append(" AND a.order_del_end_time >= SYSDATE()  ");
		}
		sb.append(" order by a.submit_datetime DESC ");
		return dao.getPageMapList(sb.toString(), params, page);
	}

	/**
	 * @category 配送
	 * @date 2015年7月14日
	 * @param list
	 * @param user
	 */
	public void dispatchDetail(OrderPack orderPack, SysUser user) {
		Session session = factory.getCurrentSession();
		
		List<OrderDetail> list = orderPack.getOrderDetailList();
		List<String> orderCodeList = new ArrayList<String>();
		
		if (list != null && !list.isEmpty()) {
			//	计算到货确认截止日期
			Date orderConfEndTime = getOrderConfEndTime();
			
			//	计算订单提交到配送时间差（分钟）
			Long orderDelTimespace = DateUtil.getDifftime(orderPack.getSubmitDatetime());
			//	计算订单确认到配送时间差（分钟）
			Long confirmDelTimespace = DateUtil.getDifftime(orderPack.getOrderConfirmTime());
			
			//	拼接配送信息
			StringBuilder sb = new StringBuilder();
			sb.append(" INSERT INTO pur_delorderinfo (del_detail_id, order_pack_id, order_code, ");
			sb.append(" 	del_count, del_datetime, order_del_timespace, confirm_del_timespace, ");
			sb.append(" 	del_user, approve_code, credential, ");
			sb.append(" 	remarks, interflow_id, order_conf_end_time, is_recepted, ");
			sb.append(" 	upd_time, upd_user, recp_code ");
			sb.append(" ) VALUES ");
			
			//	批量设置参数
			for (int i=0; i<list.size(); i++) {
				OrderDetail od = list.get(i);
				List<DispatchInfo> dis = od.getDispatchInfoList();// 批号、发票等信息
				if (dis != null && !dis.isEmpty()) {
					for (int j=0; j<dis.size(); j++) {
						String suffix = "_" + i + j;
						sb.append("(:uuid" + suffix + ", :orderPackId, :orderCode" + suffix + ",  ");
						sb.append(" :delCount" + suffix + ", :delDatetime, :orderDelTimespace" + suffix + ", ");
						sb.append(" :confirmDelTimespace" + suffix + ",  ");
						sb.append(" :delUser, :approveCode" + suffix + ", ");
						sb.append(" :credential" + suffix + ", ");
						sb.append(" :remarks" + suffix + ", :interflowId, :orderConfEndTime, 0, ");
						sb.append(" sysdate(), :userId, :recpCode) ");
						if (j < dis.size() - 1) {
							sb.append(", ");
						}
					}
					if (i < list.size() - 1) {
						sb.append(", ");
					}
				}
			}
			
			SQLQuery query = session.createSQLQuery(sb.toString());
			query.setString("userId", user.getId());
			query.setString("delUser", user.getId());
			query.setString("interflowId", orderPack.getRecpCode());	//	物流信息ID
			query.setTimestamp("delDatetime", new Date());
			query.setTimestamp("orderConfEndTime", orderConfEndTime);
			query.setString("recpCode", orderPack.getRecpCode());	//	验收单号
			query.setString("orderPackId", orderPack.getOrderPackId());
			
			//	批量参数赋值
			for (int i=0; i<list.size(); i++) {
				OrderDetail od = list.get(i);
				String orderCode = od.getOrderCode();	//	订单明细编号
				orderCodeList.add(orderCode);
				List<DispatchInfo> dis = od.getDispatchInfoList();// 批号、发票等信息
				if (dis != null && !dis.isEmpty()) {
					for (int j=0; j<dis.size(); j++) {
						DispatchInfo di = dis.get(j);
						String suffix = "_" + i + j;
						query.setString("uuid" + suffix, UUID.randomUUID().toString());
						query.setString("orderCode" + suffix, orderCode);
						query.setInteger("delCount" + suffix, di.getDelCount());
						query.setLong("orderDelTimespace" + suffix, orderDelTimespace);
						query.setLong("confirmDelTimespace" + suffix, confirmDelTimespace);
						query.setString("approveCode" + suffix, di.getApproveCode());
						query.setString("credential" + suffix, di.getCredential());
						query.setString("remarks" + suffix, di.getRemarks());
					}
				}
			}
			
			//	校验订单明细是否被配送或拒绝
			checkIsFinash(orderCodeList);
			
			//	锁定订单明细表中当前正在配送的订单明细(行锁innoDB生效)
			lockDispatchDetail(orderCodeList);
			
			//	配送信息入配送信息表
			query.executeUpdate();
			
			//	更新订单明细状态
			updateDetailStatus(orderCodeList);
			
			//	更新订单包状态
			updatePackStatus(orderPack.getOrderPackId());
			
			session.flush();
		}
	}
	/**
	 * 
	 *@category 缺货
	 *@author 邱磊
	 *@date 2015年12月13日 下午2:09:03
	 *@param 
	 *@return void
	 */
	public void shortDrug(OrderPack orderPack, SysUser user){
		List<OrderDetail> list = orderPack.getOrderDetailList();
		List<String> orderCodeList = new ArrayList<String>();
		if (list != null && !list.isEmpty()) {
			//	批量参数赋值
			for (int i=0; i<list.size(); i++) {
				OrderDetail od = list.get(i);
				String orderCode = od.getOrderCode();	//	订单明细编号
				orderCodeList.add(orderCode);
				List<DispatchInfo> dis = od.getDispatchInfoList();// 批号、发票等信息
				if (dis != null && !dis.isEmpty()) {
					for (int j=0; j<dis.size(); j++) {
						DispatchInfo di = dis.get(j);
						StringBuilder sb = new StringBuilder();
						sb.append("UPDATE pur_orderinfo set confirm_remark=:confirmRemark,order_status= :orderStatus where order_code=:orderCode");
						Map<String, Object> params = new HashMap<String, Object>();
						params.put("confirmRemark", di.getConfirmRemark());
						params.put("orderStatus",OrderDetailStatus.shortDrug.getKey());
						params.put("orderCode", orderCode);
						dao.executeSql(sb.toString(), params);
					}
				}
			}
		}
	}
	//	校验订单明细是否被配送或拒绝
	private void checkIsFinash(List<String> orderCodeList) {
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" SELECT count(*) FROM pur_orderinfo a  ");
		sb.append(" WHERE a.order_code IN (:orderCodeList) AND (a.order_status = :status or order_status = :shortSatus)");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setParameterList("orderCodeList", orderCodeList);
		query.setInteger("status", OrderPackStatus.confirmed.getKey());
		query.setInteger("shortSatus", OrderDetailStatus.shortDrug.getKey());
		BigInteger count = (BigInteger) query.uniqueResult();
		if (count.intValue() != orderCodeList.size()) {
			throw new MSException("部分商品已配送，请刷新列表后再操作！");
		}
	}
	
	//	锁定订单明细表中当前正在配送的订单明细
	private void lockDispatchDetail(List<String> orderCodeList) {
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" SELECT a.order_code FROM pur_orderinfo a  ");
		sb.append(" WHERE a.order_code IN (:orderCodeList) AND a.order_status = :status ");
		sb.append(" FOR UPDATE ");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setParameterList("orderCodeList", orderCodeList);
		query.setInteger("status", OrderPackStatus.confirmed.getKey());
		query.list();
	}
	
	//	更新订单明细状态
	private void updateDetailStatus(List<String> orderCodeList) {
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" UPDATE pur_orderinfo SET order_status = :status,confirm_remark=null ");
		sb.append(" WHERE order_code IN (:orderCodeList) ");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setParameterList("orderCodeList", orderCodeList);
		query.setInteger("status", OrderDetailStatus.dispatched.getKey());
		query.executeUpdate();
	}
	
	//	更新订单包状态
	private void updatePackStatus(String orderPackId) {
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" UPDATE pur_orderpack SET order_status = :orderStatus WHERE order_pack_id = :orderPackId ");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setString("orderPackId", orderPackId);
		if (checkAllDispatched(orderPackId)) {	//	包下无未处理的明细时，配送完成
			query.setInteger("orderStatus", OrderPackStatus.finashDispatched.getKey());
		} else {	//	包下有未处理的明细时，部分配送
			query.setInteger("orderStatus", OrderPackStatus.someDispatched.getKey());
		}
		query.executeUpdate();
	}
	
	//	判断订单包下明细是否已处理完
	private boolean checkAllDispatched(String orderPackId) {
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" SELECT COUNT(*) FROM pur_orderinfo ");
		sb.append(" WHERE order_pack_id = :orderPackId AND order_status = :orderStatus ");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setString("orderPackId", orderPackId);
		query.setInteger("orderStatus", OrderPackStatus.confirmed.getKey());
		BigInteger count = (BigInteger) query.uniqueResult();
		if (count.intValue() > 0) {
			return false;
		}
		return true;
	}
	
	//	计算到货确认截止日期
	private Date getOrderConfEndTime() {
		Map<String, Object> configMap =  getConfigMap();
		String days = (String) configMap.get(Constants.HOSP_DAY_NUM_ID);
		Date orderConfEndTime = null;
		if (StringUtils.isNotBlank(days)) {
			int day = Integer.parseInt(days, 10);
			orderConfEndTime = DateUtil.getSomeDate(day, 1);
		}
		return orderConfEndTime;
	}
	
	/**
	 * @category 获取配置参数
	 * @date 2015年7月14日
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Map<String, Object> getConfigMap() {
		Map<String, Object> map = new HashMap<String, Object>();
		Session session = factory.getCurrentSession();
		Criteria criteria = session.createCriteria(PurConfig.class);
		List<PurConfig> list = criteria.list();
		if (list != null && !list.isEmpty()) {
			for (PurConfig config : list) {
				map.put(config.getConfigId(), config.getConfigValue());
			}
		}
		return map;
	}
	
	/**
	 * @category 拒绝配送
	 * @date 2015年7月14日
	 * @param list
	 * @param user
	 */
	public void refuseDispatchDetail(OrderPack orderPack, SysUser user) {
		Session session = factory.getCurrentSession();
		
		List<OrderDetail> list = orderPack.getOrderDetailList();
		List<String> orderCodeList = new ArrayList<String>();
		
		if (list != null && !list.isEmpty()) {
			for (int i=0; i<list.size(); i++) {
				OrderDetail od = list.get(i);
				String orderCode = od.getOrderCode();	//	订单明细编号
				orderCodeList.add(orderCode);
			}
			
			//	校验订单明细是否被配送或拒绝
			checkIsFinash(orderCodeList);
			
			//	锁定订单明细表中当前正在配送的订单明细(行锁innoDB生效)
			lockDispatchDetail(orderCodeList);
			
			//	更新订单明细表状态为无法配送
			updateDetailStatusToRefuse(list, user);
			
			//	更新订单包状态
			updatePackStatusToRefuse(orderPack.getOrderPackId());
			
			session.flush();
		}
	}
	
	//	更新订单明细表状态为无法配送
	private void updateDetailStatusToRefuse(List<OrderDetail> list, SysUser user) {
		Session session = factory.getCurrentSession();
		for (OrderDetail od : list) {
			StringBuilder sb = new StringBuilder();
			sb.append(" UPDATE pur_orderinfo SET order_status = :orderStatus, ");
			sb.append(" oper_user = :userId, ");
			sb.append(" oper_datetime = sysdate(), ");
			sb.append(" confirm_remark = :confirmRemark ");
			sb.append(" WHERE order_code = :orderCode ");
			SQLQuery query = session.createSQLQuery(sb.toString());
			query.setString("orderCode", od.getOrderCode());
			query.setInteger("orderStatus", OrderDetailStatus.decline.getKey());
			query.setString("confirmRemark", od.getConfirmRemark());
			query.setString("userId", user.getId());
			query.executeUpdate();
		}
	}
	
	//	更新订单包状态
	private void updatePackStatusToRefuse(String orderPackId) {
		int orderStatus = OrderPackStatus.finishOrder.getKey();
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" UPDATE pur_orderpack SET order_status = :orderStatus WHERE order_pack_id = :orderPackId ");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setString("orderPackId", orderPackId);
		if (checkAllRefused(orderPackId)) {	//	包下明细状态全是拒绝配送时，包状态为订单完成
			orderStatus = OrderPackStatus.finishOrder.getKey();
			query.setInteger("orderStatus", orderStatus);
			query.executeUpdate();
		} else if (checkAllDispatched(orderPackId)) {	//	包下明细已全部处理完或配送或拒绝时，包状态为配送完成
			orderStatus = OrderPackStatus.finashDispatched.getKey();
			query.setInteger("orderStatus", orderStatus);
			query.executeUpdate();
		}
	}
	
	//	判断订单包下明细是否全部是拒绝配送
	@SuppressWarnings("unchecked")
	private boolean checkAllRefused(String orderPackId) {
		Session session = factory.getCurrentSession();
		StringBuilder sb = new StringBuilder();
		sb.append(" SELECT COUNT(*) totalCount, ");
		sb.append(" SUM(CASE WHEN a.order_status = :orderStatus THEN 1 ELSE 0 END) declineCount ");
		sb.append(" FROM pur_orderinfo a WHERE a.order_pack_id = :orderPackId ");
		SQLQuery query = session.createSQLQuery(sb.toString());
		query.setString("orderPackId", orderPackId);
		query.setInteger("orderStatus", OrderDetailStatus.decline.getKey());
		query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		
		Map<String, Object> map = (Map<String, Object>) query.uniqueResult();
		if (map != null) {
			BigInteger totalCount = (BigInteger) map.get("totalCount");	//	包下明细数量
			BigDecimal declineCount = (BigDecimal) map.get("declineCount");	//	包下拒绝配送的明细数量
			if (declineCount.intValue() == totalCount.intValue()) {
				return true;
			}
		}
		return false;
	}
	
}
